package mytask.dao;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import mytask.model.Project;
import mytask.model.Ticket;
import mytask.model.User;

import org.hibernate.Criteria;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.springframework.dao.support.DataAccessUtils;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.stereotype.Repository;

@Repository(value = "ticketDAO")
public class TicketDAOImpl extends GeneralDAO implements TicketDAO {

    @Override
    public void saveTicket(Ticket ticket) {
        ticket.setLastModified(new Date());

        getHibernateTemplate().saveOrUpdate(ticket);
    }

    @Override
    public Ticket getTicket(final int id) {
        return getHibernateTemplate().get(Ticket.class, id);
    }

    @Override
    @SuppressWarnings("unchecked")
    public List<Ticket> listTickets() {
        return getHibernateTemplate().find("from Ticket");
    }

    @Override
    @SuppressWarnings("unchecked")
    public List<Ticket> listTickets(final User user, final int maxResults) {
        final String query = "from Ticket as t where t.creator = ? or t.assignee = ? order by t.lastModified desc";
        final HibernateTemplate template = getHibernateTemplate();
        template.setMaxResults(maxResults);

        return template.find(query, user, user);
    }

    @Override
    @SuppressWarnings("unchecked")
    public List<Ticket> listTicketsFromAcceptedProjects(final User user, final Project project) {
        final String query = "from Ticket as t where (t.creator = ? or t.assignee = ?) and t.project = ? order by t.lastModified desc";
        final HibernateTemplate template = getHibernateTemplate();

        return template.find(query, user, user, project);
    }

    @Override
    @SuppressWarnings("unchecked")
    public List<Ticket> listTicketsFromAcceptedProjects(final User user, final List<Project> projects,
            final int maxResults) {
        if (projects.isEmpty()) {
            return new ArrayList<Ticket>();
        }
        
        int i = 0;
        final Integer[] projectIds = new Integer[projects.size()];
        for (final Project project : projects) {
            projectIds[i++] = project.getId();
        }

        final DetachedCriteria criteria = DetachedCriteria.forClass(Ticket.class);
        criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
        criteria.add(Restrictions.and(Restrictions.or(
                Restrictions.eq("creator", user), Restrictions.eq("assignee", user)), Restrictions.in("project.id", projectIds)));
        criteria.addOrder(Order.desc("lastModified"));

        final HibernateTemplate template = getHibernateTemplate();
        final int numMembers = projects.get(0).getMembers().size();
        return template.findByCriteria(criteria, 0, maxResults * numMembers);
    }

    @Override
    @SuppressWarnings("unchecked")
    public List<Ticket> listTickets(final Project project, final int offset, final int limit) {
        final HibernateTemplate template = getHibernateTemplate();
        template.setMaxResults(-1);

        final List<Ticket> tickets = template.find("from Ticket as t where t.project = ?", project);
        if (tickets.size() > offset) {
            final int endIndex = offset + limit;
            return tickets.subList(offset, tickets.size() < endIndex ? tickets.size() : endIndex);
        }

        if (tickets.size() > 0) {
            return tickets.subList(0, tickets.size() < limit ? tickets.size() : limit);
        }

        return new ArrayList<Ticket>();
    }

    @Override
    public int numTickets(final Project project) {
        return DataAccessUtils.intResult(getHibernateTemplate().find(
                "select count(*) from Ticket as t where t.project = ?", project));
    }

}